package com.zxy.ziems.server.statistics.service.impl;

import com.zxy.btp.redis.utils.RedisUtil;
import com.zxy.ziems.server.classify.pojo.entity.Classify;
import com.zxy.ziems.server.classify.pojo.entity.ClassifyDeviceProperty;
import com.zxy.ziems.server.classify.service.ClassifyDevicePropertyService;
import com.zxy.ziems.server.classify.service.ClassifyService;
import com.zxy.ziems.server.constant.enums.DictCodeEnum;
import com.zxy.ziems.server.domain.DictItem;
import com.zxy.ziems.server.dto.DataQueryDto;
import com.zxy.ziems.server.energy.pojo.vo.EleTotalSystemVo;
import com.zxy.ziems.server.energy.service.DataChartService;
import com.zxy.ziems.server.service.DictItemService;
import com.zxy.ziems.server.statistics.service.EleService;
import com.zxy.ziems.server.utils.ThreadLocalUtil;
import com.zxy.ziems.server.vo.ChartVo;
import com.zxy.ziems.server.vo.ChartYAxisVo;
import org.apache.commons.collections4.list.TreeList;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Copyright (C),
 * @ClassName: EleServiceImpl
 * @Author: yanzhiwei
 * @Description:
 * @Date: 2024/7/16 16:26
 */
@Service
public class EleServiceImpl implements EleService {

    @Autowired
    private DictItemService dictItemService;
    @Autowired
    private DataChartService dataChartService;
    @Autowired
    private ClassifyService classifyService;
    @Autowired
    private ClassifyDevicePropertyService classifyDevicePropertyService;
    @Autowired
    private RedisUtil redisUtil;

    private static String all_total = "34路+7路柴发+太阳能（高压计量）";

    @Override
    public ChartVo eleTypeAllReport(DataQueryDto dataQueryDto) {
        String key = "eleTypeAllReport" + dataQueryDto.getStartDay() + "_" + LocalDate.now().getDayOfMonth();

        ChartVo cache = (ChartVo) redisUtil.get(key);

        if (cache != null) {
            return cache;
        }

        List<DictItem> dictItemList = dictItemService.getByDictCode(DictCodeEnum.ELECTRIC_SCIENCE_DEPARTMENT_SUMMARY_OF_DEPARTMENTS_CATEGORIES.getCode());
        List<String> classifyIds = dictItemList.stream().map(m -> m.getItemCode()).collect(Collectors.toList());

        // 计算所有模块
        List<ChartYAxisVo> chartYAxisVoList = new ArrayList<>();
        List<String> xAxisList = new ArrayList<>();
        for (String classifyId : classifyIds) {
            Classify classify = classifyService.getById(classifyId);
            List<String> childrenIds = classifyService.getChildrenId(classifyId);
            dataQueryDto.setClassifyId(classifyId);
            dataQueryDto.setClassifyIdList(childrenIds);
            ChartVo chartVo = dataChartService.compareBarChart(dataQueryDto);
            List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();
            if (xAxisList.isEmpty()) {
                xAxisList = chartVo.getXAxisList();
            }

            for (ChartYAxisVo chartYAxisVo : yAxisList) {
                chartYAxisVo.setCode(classify.getClassifyName());
            }
            chartYAxisVoList.addAll(yAxisList);
        }


        // 计算合计
        ChartYAxisVo chartYAxisVo1 = getChartYAxisVo(chartYAxisVoList, xAxisList.size());
        chartYAxisVoList.add(chartYAxisVo1);

        // 增加光伏、高压、34路、低压/全厂
        ChartVo chartVo1 = eleAllReport(dataQueryDto);
        Map<String, ChartYAxisVo> collect = chartVo1.getYAxisList().stream().collect(Collectors.toMap(ChartYAxisVo::getName, v -> v));
        ChartYAxisVo chartYAxisVo2 = collect.get("光伏发电");
        chartYAxisVo2.setCode("光伏发电");
        chartYAxisVoList.add(chartYAxisVo2);

        ChartYAxisVo all = collect.get(all_total);
        all.setCode(all_total);
        chartYAxisVoList.add(all);

        ChartYAxisVo chartYAxisVo = new ChartYAxisVo(); // 低压/全厂
        BeanUtils.copyProperties(chartYAxisVo1, chartYAxisVo);
        chartYAxisVo.setName("低压/全厂");
        chartYAxisVo.setCode("低压/全厂");
        List<BigDecimal> data = chartYAxisVo1.getData();
        List<BigDecimal> data1 = all.getData();
        List<BigDecimal> resData = new ArrayList<>();
        for (int i = 0; i < data.size(); i++) {
            BigDecimal allDecimal = data1.get(i);
            BigDecimal lowDecimal = data.get(i);
            if (allDecimal.compareTo(BigDecimal.ZERO) == 0) {
                resData.add(null);
            } else {
                resData.add((lowDecimal == null ? BigDecimal.ZERO : lowDecimal).divide(allDecimal, 2, RoundingMode.HALF_UP));
            }
        }
        chartYAxisVo.setData(resData);
        chartYAxisVoList.add(chartYAxisVo);

        ChartYAxisVo e = collect.get("34路外线计量");
        e.setCode("34路外线计量");
        chartYAxisVoList.add(e);


        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(xAxisList);
        chartVo.setYAxisList(chartYAxisVoList);

        redisUtil.set(key, chartVo, 1L, TimeUnit.DAYS);

        return chartVo;
    }

    /**
     * 获取总电、光伏、34路数据
     * @param dataQueryDto
     * @return
     */
    private ChartVo eleAllReport(DataQueryDto dataQueryDto) {
        List<DictItem> dictItemList = dictItemService.getByDictCode(DictCodeEnum.ELECTRIC_SCIENCE_ALL.getCode());
        Map<String, String> classifyName = dictItemList.stream().collect(Collectors.toMap(DictItem::getItemCode, DictItem::getItemName));

        List<String> classifyIds = dictItemList.stream().map(m -> m.getItemCode()).collect(Collectors.toList());

        // 计算所有模块
        List<ChartYAxisVo> chartYAxisVoList = new ArrayList<>();
        List<String> xAxisList = new ArrayList<>();
        for (String classifyId : classifyIds) {
            Classify classify = classifyService.getById(classifyId);
            dataQueryDto.setClassifyIdList(Arrays.asList(classifyId));
            ChartVo chartVo = dataChartService.compareBarChart(dataQueryDto);
            List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();
            if (xAxisList.isEmpty()) {
                xAxisList = chartVo.getXAxisList();
            }

            for (ChartYAxisVo chartYAxisVo : yAxisList) {
                chartYAxisVo.setCode(classifyName.get(classify.getClassifyId()));
                chartYAxisVo.setName(classifyName.get(classify.getClassifyId()));
            }
            chartYAxisVoList.addAll(yAxisList);
        }

        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(xAxisList);
        chartVo.setYAxisList(chartYAxisVoList);

        return chartVo;
    }

    @Override
    public ChartVo eleTypeAllReportSys(DataQueryDto dataQueryDto) {
        String key = "eleTypeAllReportSys" + dataQueryDto.getStartDay() + "_" + LocalDate.now().getDayOfMonth();

        ChartVo cache = (ChartVo) redisUtil.get(key);

        if (cache != null) {
            return cache;
        }

        List<DictItem> dictItemList = dictItemService.getByDictCode(DictCodeEnum.ELECTRIC_SCIENCE_DEPARTMENT_SUMMARY_OF_DEPARTMENTS_CATEGORIES_SYS.getCode());
        List<String> classifyIds = dictItemList.stream().map(m -> m.getItemCode()).collect(Collectors.toList());

        // 计算变化率，开始时间减一天
        ThreadLocalUtil.put("is_sub_one_day", true);
        // 计算所有模块
        List<ChartYAxisVo> chartYAxisVoList = new ArrayList<>();
        List<String> xAxisList = new ArrayList<>();
        for (String classifyId : classifyIds) {
            Classify classify = classifyService.getById(classifyId);
            List<String> childrenIds = classifyService.getChildrenId(classifyId);
            dataQueryDto.setClassifyId(classifyId);
            dataQueryDto.setClassifyIdList(childrenIds);
            ChartVo chartVo = dataChartService.compareBarChart(dataQueryDto);
            List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();
            if (xAxisList.isEmpty()) {
                chartVo.getXAxisList().remove(0);
                xAxisList = chartVo.getXAxisList();
            }

            for (ChartYAxisVo chartYAxisVo : yAxisList) {
                List<BigDecimal> ratio = new ArrayList<>();
                List<BigDecimal> data = chartYAxisVo.getData();
                for (int i = 1; i < data.size(); i++) {
                    BigDecimal bigDecimal = data.get(i-1);
                    if (bigDecimal.compareTo(BigDecimal.ZERO) == 0) {
                        ratio.add(null);
                    } else {
                        ratio.add(data.get(i).divide(bigDecimal, 4, RoundingMode.HALF_UP).subtract(BigDecimal.ONE));
                    }
                }
                data.remove(0);
                chartYAxisVo.setRatio(ratio);
                chartYAxisVo.setCode(classify.getClassifyName());
            }
            chartYAxisVoList.addAll(yAxisList);
        }


        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(xAxisList);
        chartVo.setYAxisList(chartYAxisVoList);

        redisUtil.set(key, chartVo, 1L, TimeUnit.DAYS);

        return chartVo;
    }

    @Override
    public ChartVo eleTypeAllReportBuilding(DataQueryDto dataQueryDto) {

        // 计算所有模块
        List<ChartYAxisVo> chartYAxisVoList = new ArrayList<>();
        List<String> xAxisList = new ArrayList<>();

        List<DictItem> dictItemList1 = dictItemService.getByDictCode(DictCodeEnum.ELECTRIC_SCIENCE_AND_TECHNOLOGY_DEPARTMENT_SUMMARY_BUILDING.getCode());
        List<String> classifyId1s = dictItemList1.stream().map(m -> m.getItemCode()).collect(Collectors.toList());
        for (String classifyId : classifyId1s) {
            Classify classify = classifyService.getById(classifyId);
            dataQueryDto.setClassifyId(classifyId);
            ChartVo chartVo = dataChartService.thisCycleData(dataQueryDto);
            List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();
            if (xAxisList.isEmpty()) {
                xAxisList = chartVo.getXAxisList();
            }

            for (ChartYAxisVo chartYAxisVo : yAxisList) {
                chartYAxisVo.setCode(classify.getClassifyName());
            }
            chartYAxisVoList.addAll(yAxisList);
        }


        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(xAxisList);
        chartVo.setYAxisList(chartYAxisVoList);

        return chartVo;
    }

    /*@Override
    public EleTotalSystemVo eleTypeAllReportSystem(DataQueryDto dataQueryDto) {

        // 计算所有模块
        List<DictItem> dictItemList1 = dictItemService.getByDictCode(DictCodeEnum.SUMMARY_OF_ELECTRONIC_SCIENCE_AND_TECHNOLOGY_DEPARTMENTS_SYSTEM.getCode());
        List<String> classifyId1s = dictItemList1.stream().map(m -> m.getItemCode()).collect(Collectors.toList());
        List<BigDecimal> valueList = new ArrayList<>();
        List<String> titleList = new ArrayList<>();
        for (String classifyId : classifyId1s) {
            Classify classify = classifyService.getById(classifyId);
            dataQueryDto.setClassifyId(classifyId);
            ChartVo chartVo = dataChartService.thisCycleData(dataQueryDto);
            List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();


            BigDecimal bigDecimal = BigDecimal.ZERO;
            for (ChartYAxisVo chartYAxisVo : yAxisList) {
                bigDecimal.add(chartYAxisVo.getData().get(0));
            }
            titleList.add(classify.getClassifyName());
            valueList.add(bigDecimal);

        }

        EleTotalSystemVo eleTotalSystemVo = EleTotalSystemVo.builder().titleList(titleList).valueList(valueList).build();


        return eleTotalSystemVo;
    }*/

    @Override
    public EleTotalSystemVo eleTypeAllReportSystem(DataQueryDto dataQueryDto) {

        String key = "eleTypeAllReportSystem_" + dataQueryDto.getStartDay() + "_" + LocalDate.now().getDayOfMonth();

        EleTotalSystemVo cache = (EleTotalSystemVo) redisUtil.get(key);

        if (cache != null) {
            return cache;
        }

        ChartVo chartVo = eleTypeAllReport(dataQueryDto);

        List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();

        // 过滤掉光伏、34路、全厂
        LinkedHashMap<String, ChartYAxisVo> yMap = yAxisList.stream().collect(Collectors.toMap(ChartYAxisVo::getName, v -> v, (o1, o2) -> o1, LinkedHashMap::new));
        ChartYAxisVo chartYAxisVo1 = yMap.get(all_total);
        ChartYAxisVo chartYAxisVo2 = yMap.get("低压合计");
        yMap.remove(all_total);
        yMap.remove("光伏发电");
        yMap.remove("低压/全厂");

        chartVo.getXAxisList().remove("光伏发电");

        // 计算低压分类汇总
        List<BigDecimal> valueList = new ArrayList<>();
        List<BigDecimal> ratioList = new ArrayList<>();
        List<String> titleList = new ArrayList<>();


        BigDecimal total = BigDecimal.ZERO;
        for (Map.Entry<String, ChartYAxisVo> stringChartYAxisVoEntry : yMap.entrySet()) {
            ChartYAxisVo chartYAxisVo = stringChartYAxisVoEntry.getValue();
            BigDecimal sum = chartYAxisVo.getData().stream().filter(o -> o != null).reduce(BigDecimal.ZERO, BigDecimal::add);
            valueList.add(sum);
            total = total.add(sum);
            titleList.add(chartYAxisVo.getName());
        }

        // 处理占比
        for (int i = 0; i < titleList.size() - 2; i++) {
            ratioList.add(
                    total.compareTo(BigDecimal.ZERO)==0 ? null : valueList.get(i).divide(total, 4, RoundingMode.HALF_UP)
            );
        }

        // 设置高压合计
        BigDecimal low = chartYAxisVo2.getData().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        // 设置高压合计
        titleList.add(all_total);
        BigDecimal high = chartYAxisVo1.getData().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        valueList.add(high);
        titleList.add("低压/计量");
        valueList.add(
                high.compareTo(BigDecimal.ZERO)==0 ? null: low.divide(high, 2, RoundingMode.HALF_UP)
        );

        EleTotalSystemVo eleTotalSystemVo = EleTotalSystemVo.builder().titleList(titleList)
                .valueList(valueList).ratioList(ratioList).build();

        redisUtil.set(key, eleTotalSystemVo, 1L, TimeUnit.DAYS);

        return eleTotalSystemVo;
    }

    @Override
    public EleTotalSystemVo eleTypeAllReportSysRatio(DataQueryDto dataQueryDto) {

        String key = "eleTypeAllReportSysRatio_" + dataQueryDto.getStartDay() + "_" + LocalDate.now().getDayOfMonth();

        EleTotalSystemVo cache = (EleTotalSystemVo) redisUtil.get(key);

        if (cache != null) {
            return cache;
        }

        ChartVo chartVo = eleTypeAllReportSys(dataQueryDto);

        List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();
        yAxisList.remove(0);

        // 计算低压分类汇总
        List<BigDecimal> valueList = new ArrayList<>();
        List<BigDecimal> ratioList = new ArrayList<>();
        List<String> titleList = new ArrayList<>();
        Map<String, BigDecimal> valueMap = new HashMap<>();

        BigDecimal total = BigDecimal.ZERO;
        for (ChartYAxisVo chartYAxisVo : yAxisList) {
            BigDecimal sum = chartYAxisVo.getData().stream().filter(o -> o != null).reduce(BigDecimal.ZERO, BigDecimal::add);
            total = total.add(sum);
            valueMap.put(chartYAxisVo.getName(), sum);
        }

        valueMap.entrySet()
                .stream()
                .sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new
                )).forEach((k, v) -> {
                    titleList.add(k);
                    valueList.add(v);
                });

        // 处理占比
        for (int i = 0; i < titleList.size(); i++) {
            ratioList.add(total.equals(BigDecimal.ZERO) ? null : valueList.get(i).divide(total, 4, RoundingMode.HALF_UP));
        }

        EleTotalSystemVo eleTotalSystemVo = EleTotalSystemVo.builder().titleList(titleList)
                .valueList(valueList).ratioList(ratioList).build();

        redisUtil.set(key, eleTotalSystemVo, 1L, TimeUnit.DAYS);

        return eleTotalSystemVo;
    }

    @Override
    public ChartVo eleTypeOneReportBuilding(DataQueryDto dataQueryDto) {
        String classifyId = dataQueryDto.getClassifyId();
        // 计算所有模块
        List<ChartYAxisVo> chartYAxisVoList = new ArrayList<>();
        List<String> xAxisList = new ArrayList<>();


        Classify classify = classifyService.getById(classifyId);
        List<String> childrenIds = classifyService.getChildrenId(classifyId);
        dataQueryDto.setClassifyId(classifyId);
        dataQueryDto.setClassifyIdList(childrenIds);
        ChartVo chartVo = dataChartService.compareBarChart(dataQueryDto);
        List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();


        chartYAxisVoList.addAll(yAxisList);

        // 计算合计
        ChartYAxisVo chartYAxisVo1 = getChartYAxisVo(chartYAxisVoList, xAxisList.size());
        chartYAxisVoList.add(chartYAxisVo1);

        chartVo.setYAxisList(chartYAxisVoList);

        return chartVo;
    }


    @NotNull
    private static ChartYAxisVo getChartYAxisVo(List<ChartYAxisVo> yAxisList, int size) {
        List<BigDecimal> result = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            BigDecimal sum = BigDecimal.ZERO;
            for (ChartYAxisVo chartYAxisVo : yAxisList) {
                BigDecimal bigDecimal = chartYAxisVo.getData().get(i);
                sum = sum.add(bigDecimal);
            }
            result.add(sum);
        }

        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName("低压合计");
        chartYAxisVo.setCode("低压合计");
        chartYAxisVo.setData(result);
        return chartYAxisVo;
    }

    @Override
    public ChartVo eleTypeOneReport(DataQueryDto dataQueryDto) {
        List<ClassifyDeviceProperty> classifyDeviceProperty = classifyDevicePropertyService.getByClassId(dataQueryDto.getClassifyId());

        List<DataQueryDto.ClassDevice> collect = classifyDeviceProperty.stream().map(m -> {
            DataQueryDto.ClassDevice classDevice = new DataQueryDto.ClassDevice();
            classDevice.setClassifyId(m.getClassifyId());
            classDevice.setDeviceId(m.getDeviceId());
            return classDevice;
        }).collect(Collectors.toList());

        dataQueryDto.setDeviceList(collect);

        dataQueryDto.setClassifyId(null);
        ChartVo chartVo = dataChartService.deviceCompareLineChart(dataQueryDto);

        // 计算合计
        List<ChartYAxisVo> yAxisList = chartVo.getYAxisList();
        // todo 临时设置位号
        for (ChartYAxisVo chartYAxisVo : yAxisList) {
            chartYAxisVo.setTagNumber(null);
        }
        ChartYAxisVo chartYAxisVo = getChartYAxisVo(yAxisList, chartVo.getXAxisList().size());

        yAxisList.add(chartYAxisVo);
        chartVo.setYAxisList(yAxisList);

        return chartVo;
    }

}
